//
//  EWEFilter.swift
//  Auscultation
//
//  Created by 来 on 2021/1/18.
//

import Foundation

class EWEFilter: NSObject {

    // 心音参数
    static var ORDER_HT: Int = 4;
    static var PARA_NUM_HT: [Double] = [
      1,
      -3.69905687174103,
      5.14920434916213,
      -3.19928074902097,
      0.74918096748416,
    ]
    static var PARA_DEN_HT: [Double] = [
      0.00908576605455529,
      0,
      -0.0181715321091106,
      0,
      0.00908576605455529,
    ]

    // 肺音参数
    static var ORDER_BR: Int = 4;
    static var PARA_NUM_BR: [Double] = [
      1,
      -3.27556162543813,
      4.08778672107216,
      -2.32483150340646,
      0.513981894219675,
    ]
    static var PARA_DEN_BR: [Double] = [
      0.0412535372417203,
      0,
      -0.0825070744834407,
      0,
      0.0412535372417203,
    ]

    // 混合音参数
    static var ORDER_MX: Int = 4;
    static var PARA_NUM_MX: [Double] = [
      1,
      -3.15341359229553,
      3.75746315698312,
      -2.03953411411848,
      0.43590739824434,
    ]
    static var PARA_DEN_MX: [Double] = [
      0.0604985076309407,
      0,
      -0.120997015261881,
      0,
      0.0604985076309407,
    ]
    
    // 心音滤波数组
    static var filter_x_HT: [Double] = Array.init(repeating: 0, count: ORDER_HT)
    static var filter_y_HT: [Double] = Array.init(repeating: 0, count: ORDER_HT)

    // 肺音滤波数组
    static var filter_x_BR: [Double] = Array.init(repeating: 0, count: ORDER_BR)
    static var filter_y_BR: [Double] = Array.init(repeating: 0, count: ORDER_BR)

    // 混合音滤波数组
    static var filter_x_MX: [Double] = Array.init(repeating: 0, count: ORDER_MX)
    static var filter_y_MX: [Double] = Array.init(repeating: 0, count: ORDER_MX)
    
    static func clear() {
        filter_x_HT = Array.init(repeating: 0, count: ORDER_HT)
        filter_y_HT = Array.init(repeating: 0, count: ORDER_HT)
        filter_x_BR = Array.init(repeating: 0, count: ORDER_BR)
        filter_y_BR = Array.init(repeating: 0, count: ORDER_BR)
        filter_x_MX = Array.init(repeating: 0, count: ORDER_MX)
        filter_y_MX = Array.init(repeating: 0, count: ORDER_MX)
    }

    /**
     * @description: 心音滤波处理方法
     * @param {*} dataIn float 音频归一化数值
     * @return {dataOut}
     */
    static func filter_HT(_ dataIn: String) -> String {
        let dataIns = getStrCountArray(dataIn, 4)
        
        var dataOutArr: [UInt8] = []
        dataIns.forEach { (str) in
            let inD = getComplement(str)
            var outD: Double = 0.0
            for i in 0..<ORDER_HT {
                outD += PARA_DEN_HT[i + 1] * filter_x_HT[i] - PARA_NUM_HT[i + 1] * filter_y_HT[i]
            }
            outD += PARA_DEN_HT[0] * inD
            
            for i in 1..<ORDER_HT {
                let j = ORDER_HT - i
                filter_x_HT[j] = filter_x_HT[j - 1]
                filter_y_HT[j] = filter_y_HT[j - 1]
            }
            filter_x_HT[0] = inD
            filter_y_HT[0] = outD
            
            let filterValue = getComplementCode(round(outD * 32768))
            dataOutArr.append(UInt8(filterValue % 256))
            dataOutArr.append(UInt8(Int(filterValue / 256)))
        }
        let dataO = Data.init(bytes: dataOutArr, count: dataOutArr.count)
        return dataO.lgf_HexString
    }
    
    static func getComplementCode(_ data: Double) -> Int {
        if data < 0 {
            return 65535 + Int(data)
        } else if data == 0 {
            return 0
        }
        return Int(data)
    }

    static func getComplement(_ str: String) -> Double {
        let start = str.index(str.startIndex, offsetBy: 2)
        let end = str.index(str.endIndex, offsetBy: -2)
        let leftStr = str[str.startIndex..<end]
        let rightStr = str[start..<str.endIndex]
        let LInt = changeToInt(String(leftStr))
        var RInt = changeToInt(String(rightStr))
        
        var res: Double = 0
        if RInt >= 128 {
            RInt = RInt - 128
            res = Double(RInt * 256 + LInt)
            res = res - 32767
        } else {
            res = Double(RInt * 256 + LInt)
        }
        res  = (res / 32768.0) * 10.0;
        if (res < -0.55) {
          res = -0.55;
        } else if (res > 0.55) {
          res = 0.55;
        }
        return res
    }

    static func changeToInt(_ num: String) -> Int {
        let str = num.uppercased
        var sum = 0
        for i in str().utf8 {
            sum = sum * 16 + Int(i) - 48
            if i >= 65 {
                sum -= 7
            }
        }
        return sum
    }

    static func getStrCountArray(_ str: String, _ count: Int) -> [String] {
        var array: [String] = []
        var ffp = ""
        var ffi = 0
        str.forEach { (c) in
            ffp += String(c)
            ffi += 1
            if ffi % count == 0 {
                array.append(ffp)
                ffp = ""
                ffi = 0
            }
        }
        return array
    }

}
